/* hal_i2c.c */
#include "hal_i2c.h"
#include "fsl_reset.h"

#define I2C_DEV_ADDR_R_MASK  0x1
#define I2C_DEV_ADDR_W_MASK  0x0

typedef enum
{
    eI2C_MasterCtrlCmd_GoXfer            = I2C_MSTCTL_MSTCONTINUE_MASK, /* 软件触发发送缓冲区中的数据到总线上 */
    eI2C_MasterCtrlCmd_SendDataWithSTART = I2C_MSTCTL_MSTSTART_MASK,    /* 在接下来发送数据时，在数据之前发送START */
    eI2C_MasterCtrlCmd_SendSTOP          = I2C_MSTCTL_MSTSTOP_MASK,     /* 在接下来发送数据是，在数据之后发送STOP */
} I2C_MasterCtrlcmd_T;

/* 硬件自动维护I2C通信协议的各个阶段的状态，便于软件根据这个状态值进行后续的操作 */
typedef enum
{
    eI2C_MasterState_Idle    = 0, /* 当前总线空闲，可以发送新的数据 */
    eI2C_MasterState_RxReady = 1, /* 在开始后发送设备地址和读操作码之后收到了应答，可以开始读取数据
                                     在读模式中，不需要向数据缓冲寄存器中写数，只要触发传输过程，硬件会自动在SCL上发出8个脉冲
                                     之后通知主机可以从数据缓冲寄存器中取数 */
    eI2C_MasterState_TxReady = 2, /* 在开始后发送设备地址和写操作码之后收到了应答，可以开始写数据
                                     在写模式中，先向数据缓冲寄存器中写数，然后触发传输过程，硬件会自动在SCL上发出8个脉冲
                                     的同时将数据缓冲寄存器中的数据上传到SDA信号线上 */
    eI2C_MasterState_NACKAddr = 3, /* 主机发送设备地址后未收到从机的应答，这是一种通信过程中的错误状态 */
    eI2C_MasterState_NACKData = 4, /* 主机在发送数据后未收到从机的应答，这是一种通信过程中的错误状态 */
} I2C_MasterState_T;

typedef enum
{
    /* MasterPending标志置位表示主机当前已经处于待命状态，可以接受进一步的触发执行传输动作 */
    eI2C_StatusFlag_MasterPending = I2C_STAT_MSTPENDING_MASK,

    /* 主机失去仲裁 */
    eI2C_StatusFlag_MasterLostArbitration = I2C_STAT_MSTARBLOSS_MASK,

    /* 主机发送START和STOP的时候发生错误 */
    eI2C_StatusFlag_MasterStartStopError = I2C_STAT_MSTSTSTPERR_MASK,
} I2C_StatusFlag_T;

static bool I2C_SetupFlexcommAsI2C(I2C_Type *base)
{
    uint32_t cI2cBaseAddrs[] = I2C_BASE_ADDRS;
    uint32_t cFlexcommBaseAddrs[] = FLEXCOMM_BASE_ADDRS;
    reset_ip_name_t cFlexcommResetCmds[] = FLEXCOMM_RSTS;
    uint32_t comIdx; /* Get the index flexcomm port. */
    FLEXCOMM_Type *flexcommBase;

    /* 使用倒排索引定位Flexcomm的访问地址. */
    for ( comIdx = 0U; comIdx < (sizeof(cI2cBaseAddrs)/sizeof(cI2cBaseAddrs[0])); comIdx++ )
    {
        if ((uint32_t)(base) == cI2cBaseAddrs[comIdx])
        {
            break; /* 传入地址不匹配有效的访问入口 */
        }
    }
    if ( comIdx >= (sizeof(cI2cBaseAddrs)/sizeof(cI2cBaseAddrs[0])) )
    {
        return false;
    }
    flexcommBase = (FLEXCOMM_Type *)cFlexcommBaseAddrs[comIdx];

    /* 配置Flexcomm为I2C模式 */
    RESET_PeripheralReset(cFlexcommResetCmds[comIdx]); /* 复位Flexcomm接口配置 */
    flexcommBase->PSELID = FLEXCOMM_PSELID_PERSEL(0x2); /* 选择为I2C通信模式 */

    return true;
}

void I2C_InitMaster(I2C_Type *base, uint32_t busClkHz, uint32_t baudrate)
{
    /* 配置为Master模式 */
    base->CFG = I2C_CFG_MSTEN_MASK;

    /* 配置波特率时钟
     * 由于I2C总线的特性，总线时钟由主机提供，因此不需要特别精确地满足要求。一般来说，较低的100kHz能够满足绝大多数需求。
     * 此处就设定目标通信波特率100kHz作为典型应用值。
     */
    base->CLKDIV = busClkHz / 500000U - 1U; /* 12MHz的Flexcomm时钟频率获得400kHz对应分频值为5 */
    base->MSTTIME = I2C_MSTTIME_MSTSCLLOW() | I2C_MSTTIME_MSTSCLHIGH(1);


}

void I2C_SetupMasterInterruptMode(I2C_Type *base, bool enable)
{

}

/* devAddr为有效的7-bit设备地址，移位并填充读写方向的控制位在函数内部实现 */
bool I2C_MasterWriteByteBlocking(I2C_Type *base, uint8_t devAddr, uint8_t regAddr, uint8_t regVal)
{
    devAddr = (devAddr << 1U) | I2C_DEV_ADDR_W_MASK;

    /* 等待总线空闲 */
    while (0U == (eI2C_StatusFlag_MasterPending & I2C_GetStatusFlags(base)))
    {} /* 等待从机应答表示发送过程完成 */
    if (eI2C_MasterState_Idle != I2C_GetMasterCurState(base))
    {
        return false;
    }

    /* 发送START及设备地址 */
    I2C_MasterPutData(base, devAddr);
    I2C_MasterSetCtrlCmd(base, eI2C_MasterCtrlCmd_SendDataWithStart);
    while (0U == (eI2C_StatusFlag_MasterPending & I2C_GetStatusFlags(base)))
    {} /* 等待从机应答表示发送过程完成 */
    if (eI2C_MasterState_TxReady != I2C_GetMasterCurState(base))
    {
        return false;
    }

    /* 发送寄存器地址 */
    I2C_MasterPutData(base, regAddr);
    I2C_MasterSetCtrlCmd(base, eI2C_MasterCtrlCmd_GoXfer);
    while (0U == (eI2C_StatusFlag_MasterPending & I2C_GetStatusFlags(base)))
    {} /* 等待从机应答表示发送过程完成 */
    if (eI2C_MasterState_TxReady != I2C_GetMasterCurState(base))
    {
        return false;
    }

    /* 发送即将写入寄存器的数据内容 */
    I2C_MasterPutData(base, regVal);
    I2C_MasterSetCtrlCmd(base, eI2C_MasterCtrlCmd_GoXfer);
    while (0U == (eI2C_StatusFlag_MasterPending & I2C_GetStatusFlags(base)))
    {} /* 等待从机应答表示发送过程完成 */
    if (eI2C_MasterState_TxReady != I2C_GetMasterCurState(base))
    {
        return false;
    }

    /* 发送STOP */
    I2C_MasterSetCtrlCmd(base, eI2C_MasterCtrlCmd_SendSTOP);
    while (0U == (eI2C_StatusFlag_MasterPending & I2C_GetStatusFlags(base)))
    {} /* 等待从机应答表示发送过程完成 */
    if (eI2C_MasterState_Idle != I2C_GetMasterCurState(base))
    {
        return false;
    }
    return true;
}

void I2C_MasterReadByteBlocking(I2C_Type *base, uint8_t devAddr, uint8_t regAddr, uint8_t &val)
{

}

/*
 * 原子操作函数
 */

/* 返回值对应I2C_StatusFlag_T类型的枚举值 */
uint32_t I2C_GetStatusFlags(I2C_Type *base)
{
    return (base->STAT & ~I2C_STAT_MSTSTATE_MASK);
}

/* 查看当前I2C通信到什么阶段了
 * 返回值对应I2C_MasterState_T类型的枚举值
 */
uint32_t I2C_GetMasterCurState(I2C_Type *base)
{
    return (base->STAT & I2C_STAT_MSTSTATE_MASK) >> I2C_STAT_MSTSTATE_SHIFT;
}

void I2C_MasterSetCtrlCmd(I2C_Type *base, I2C_MasterCtrlcmd_T cmd)
{
    base->MSTCTL = cmd;
}

void I2C_MasterPutData(I2C_Type *base, uint8_t dat)
{
    base->MSTDAT = dat;
}

uint8_t I2C_MasterGetData(I2C_Type *base)
{
    return (uint8_t)(base->MSTDAT);
}


/* EOF. */

